// node.hpp
//

#ifndef _NODE_HPP
#define _NODE_HPP

#include "base.hpp"



class RenderContext;
class Model;
class Texture;
class SceneView;



// NodeData
//
struct NodeData
{
  virtual void render_prepare ( SceneView &scene_view ) = 0;
  virtual void render ( RenderContext &context ) = 0;
};



// NDataNone
//
struct NDataNone : public NodeData
{
  virtual void render_prepare ( SceneView &scene_view ) {}
  virtual void render ( RenderContext &rc ) {}
};



// NDataScene
//
struct NDataScene : public NodeData
{
  virtual void render_prepare ( SceneView &scene_view );
  virtual void render ( RenderContext &rc );
};



// NDataLight
//
struct NDataLight : public NodeData
{
  virtual void render_prepare ( SceneView &scene_view );
  virtual void render ( RenderContext &rc );

  wgl::Light wgl_light{};
};



// NDataEntity
//
struct NDataEntity : public NodeData
{
  NDataEntity ( Model &model,
                wgl::Material &material,
                Texture &texture,
                EntityGroup group );

  NDataEntity ( Model &model,
                EntityGroup group );

  void set_visible ( bool v ) { visible = v; }
  
  virtual void render_prepare ( SceneView &scene_view );
  virtual void render ( RenderContext &rc );

  Model &model;
  wgl::Material *material{};
  Texture *texture{};
  EntityGroup group{};
  wgl::Transfo transfo{};
  bool visible{true};
};



// Node
//
class Node
{
  struct Iterator
  {
    Node *node;

    Iterator ( Node *node ) : node(node) {}

    Node *operator* () { return node; }
    bool operator== ( Iterator &it ) { return node == it.node; }
    Iterator &operator++ () { GLT_ASSERT(node); node = node->next; return *this; }
    Iterator  operator++ (int) { GLT_ASSERT(node); Node *last = node; node = node->next; return Iterator{last}; }
  };
  
public:
  Node ( Node & ) = delete;
  Node ( Node && ) = delete;
  
  Node ( Node *parent=nullptr );
  Node ( NodeData &data,
         Node *parent=nullptr );
  ~Node ();

  NodeData &get_data () { return data; }
  
  void set_data ( NodeData &data );

  Iterator begin () { return Iterator{children}; }
  Iterator end () { return Iterator{nullptr}; }

  void add_child ( Node &child );
  void remove_child ( Node &child );

private:
  NodeData &data;
  
  Node *parent{};
  Node *children{};
  Node *children_tail{};
  Node *prev{};
  Node *next{};
};



#endif
